package com.youbenzi.dockerpool;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

import com.spotify.docker.client.DefaultDockerClient;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.DockerClient.AttachParameter;
import com.spotify.docker.client.LogMessage;
import com.spotify.docker.client.LogStream;
import com.spotify.docker.client.exceptions.DockerCertificateException;
import com.spotify.docker.client.exceptions.DockerException;

/**
 * docker 工厂抽象类，实现接口方法的流程
 * @author yangyingqiang
 * @time 2017年6月9日 下午6:26:48
 */
public abstract class AbstractDockerFactory implements DockerFactory {
	
	@Override
	public void runContainer(String type, String host, int visitPort) throws IOException {
		try (DockerClient docker = DefaultDockerClient.fromEnv().build()) {
			Register.increase(type, host);	//容器启动前，就通知注册中心登记多一个连接数
			createAndStartContainer(type, host, visitPort, docker);
			fullyUp(type, host, visitPort, docker);
		} catch (DockerCertificateException | DockerException | InterruptedException e) {
			//容器启动失败，收拾残局
			removeContainer(type, host, visitPort);	
			Register.release(type, host);
			e.printStackTrace();
		}
	}
	
	/**
	 * 容器完全启动
	 * @param type
	 * @param host
	 * @param visitPort
	 * @param docker
	 * @throws DockerException
	 * @throws InterruptedException
	 */
	private void fullyUp(String type, String host, int visitPort, DockerClient docker) 
			throws DockerException, InterruptedException {

		String containerName = containerName(type, host, visitPort);
		LogStream stream = docker.attachContainer(containerName, AttachParameter.LOGS, 
				AttachParameter.STREAM, AttachParameter.STDOUT, AttachParameter.STDERR);
		while (stream.hasNext()) {
			LogMessage message = stream.next();
			ByteBuffer bb = message.content();
			String info = buff2String(bb);
			if(isFullyUpByLogInfo(info)) {
				//容器完全启动，才在注册中心登记容器的详细信息
				Register.registe(type, host, visitPort);
				return;
			}
		}
	}
	
	private String buff2String(ByteBuffer buffer) {
		Charset charset = null;
		CharsetDecoder decoder = null;
		CharBuffer charBuffer = null;
		try {
			charset = Charset.forName("UTF-8");
			decoder = charset.newDecoder();
			charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
			return charBuffer.toString();
		} catch (Exception ex) {
			ex.printStackTrace();
			return "error";
		}
	}
	
	/**
	 * 创建并启动docker 容器
	 * @param type
	 * @param host
	 * @param visitPort
	 * @param docker
	 * @throws IOException
	 * @throws DockerException
	 * @throws InterruptedException
	 */
	public abstract void createAndStartContainer(String type, String host, int visitPort, 
			DockerClient docker) throws IOException, DockerException, InterruptedException;
	
	/**
	 * 通过docker 日志判断容器是否已完全启动
	 * @param logInfo
	 * @return
	 */
	public abstract boolean isFullyUpByLogInfo(String logInfo);
	
	/**
	 * 容器名称
	 * @param type
	 * @param host
	 * @param visitPort
	 * @return
	 */
	public abstract String containerName(String type, String host, int visitPort);
}
